/**
* Copyright 2009 Waag Society <http://www.waag.org>
* This file is part of Annotrax.
*
* Annotrax is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Annotrax is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Annotrax.
* If not, see http://www.gnu.org/licenses/gpl.html
*/

(function($){
	var AtHScaler = function( element, config ){this.initialize( element, config )};
	AtHScaler.prototype = {
		element: {},
		config: {},

		/**
		 * constructor: create htmlneeded, bind event listeners and set initial position
		 */
		initialize: function( element, config ){
			this.element = element;
			this.config  = $.extend( this.config, config );

			this.createHScaler();

			this.bindEvent( document.window, 'mousemove', 'onMousemove');
			this.bindEvent( document.window, 'mouseup', 'onMouseUp' );
			// this handles the new FF3 drag-drop api. the mouseup is never fired when
			// drag drop is activated, thus call mouseUp on drag start as a workaround
			this.bindEvent( document.window, 'dragstart', 'onMouseUp' );

			this.bindEvent( this.elements.container, 'mousedown', 'moveGripStart' );
			this.bindEvent( this.elements.resizeRight, 'mousedown', 'resizeGripStart' );
			this.bindEvent( this.elements.resizeLeft, 'mousedown', 'resizeGripStart' );

			this.position( 50, 50 );
		},

		/**
		 * event handler: toggle resize.
		 */
		resizeGripStart: function( evt ){
			// cancel bubbling: moves up to the grip otheriwse
			evt.stopPropagation();

			this.moveStart 		= false;
			this.resizeStart 	= true;

			this.resizeTo = 1;

			if( $(evt.target).hasClass('atHScalerGripResizeLeft')){
				this.resizeTo = -1;
			}
		},

		/**
		 * event handler: toggle move
		 */
		moveGripStart: function( evt ){
			this.resizeStart = false;
			this.moveStart = true;
		},

		/**
		 * event handler: stop move/resize.
		 */
		onMouseUp: function( evt ){
			this.resizeStart = false;
			this.moveStart = false;
		},

		/**
		 * save mouseX and calculate delta if needed.
		 */
		onMousemove: function( evt, self ){
			if( ! this.prevX ){
				this.prevX = evt.clientX;
			}
			else if( this.moveStart || this.resizeStart ){
				this.deltaX = evt.clientX - this.prevX;

				if( this.moveStart ){
					this.moveGrip( evt );
				}
				else if( this.resizeStart ){
					this.resizeGrip( evt );
				}
			}

			this.prevX  = evt.clientX;
		},

		/**
		 * logic on movement: check for bounds and initate position.
		 */
		moveGrip: function( evt ){
			var max 	 = this.getContainerWidth();
			var left 	 = parseInt($(this.elements.grip).css('left')) + this.deltaX;
			var width 	 = this.getGripWidth();

			if( left >= 0 && left + width <= max ){
				this.position( left, max - (left + width ));
			}
		},

		/**
		 * logic for resizing: the resizeTo parameter decides in wich direction
		 */
		resizeGrip: function( evt ){
			var left	= parseInt( $(this.elements.grip).css('left') );
			var right 	= parseInt( $(this.elements.grip).css('right') );

			if( this.resizeTo > 0 && right - this.deltaX > 0 ){
				this.position( left, ( right - this.deltaX ) );
			}
			else if( this.resizeTo < 0 && left - this.deltaX > 0 ){
				this.position( left + this.deltaX, right );
			}
		},

		/**
		 * move the grip into new position
		 */
		position: function( left, right ){
			left	= left < 0 ? 0 : left;
			right	= right < 0 ? 0 : right;

			var max 	= this.getContainerWidth();
			var width	= this.calculateGripWidth( max - left - right );

			if( width < max ){
				$(this.elements.grip).css({
					left: left + 'px',
					right: right + 'px',
					width: width + 'px',
					top: 0,
					bottom: 0
				});
			}
		},

		/**
		 * cache the width of the container, so we don't need to look it up frequently
		 */
		getContainerWidth: function(){
			if( typeof this.containerWidth == 'undefined' ){
				this.containerWidth = $(this.elements.container).width();
			}

			return this.containerWidth;
		},

		/**
		 * return width INCLUDING BODER WIDTH! because #$Q%#@! jquery doesn't automatically
		 */
		getGripWidth: function(){
			var innerWidth = $(this.elements.grip).innerWidth();// + parseInt($(this.elements.grip).css('borderWidth'));
			var leftBorder = parseInt( $(this.elements.grip).css('border-right-width') );
			var rightBorder = parseInt( $(this.elements.grip).css('border-left-width') );

			return innerWidth + leftBorder + rightBorder;
		},

		/**
		 * return width without the borders
		 */
		calculateGripWidth: function( width ){
			var leftBorder = parseInt( $(this.elements.grip).css('border-right-width') );
			var rightBorder = parseInt( $(this.elements.grip).css('border-left-width') );

			width = width - leftBorder - rightBorder;
			return width;
		},

		/**
		 * create the html needed to display the widget.
		 */
		createHScaler: function(){
			for( key in this.config.attr ){
				this.config.attr[key] = $(this.element).attr(key);
			}

			if( this.config.attr.id == '' ){
				this.config.attr.id = identify();
			}

			var cssw = $(this.element).css('width');
			var cssh = $(this.element).css('height');
			var height = $(this.element).height();
			var width  = $(this.element).width();

			var resizeLeft 	= $('<div></div>')
							.addClass('atHScalerGripResizeLeft')
							.css({width: '10px', left: 0, cursor: 'e-resize'});
			var resizeRight = $('<div></div>')
							.addClass('atHScalerGripResizeRight')
							.css({width: '10px', right: 0, cursor: 'w-resize'});
			var innerGrip   = $('<div></div>')
							.addClass('atHScalerInnerGrip')
							.css({height: '100%', width:'100%', position: 'relative'})
							.append(resizeLeft)
							.append(resizeRight);
			var grip	  = $('<div></div>')
							.addClass('atHScalerGrip')
							.append( innerGrip )
							.css({cursor: 'move', border: '2px outset #999', backgroundColor: '#ccc' });
			var container = $('<div></div>')
							.attr(this.config.attr)
							.css({position: 'relative'})
							.addClass('atHScalerEnabled')
							.append(grip);

			var list = [resizeLeft, resizeRight, grip];
			for( var i = 0; i < list.length; i++ ){
				$(list[i]).css({
					position: 'absolute',
					top: 0,
					bottom: 0
				});
			}

			$(this.element).replaceWith(container);

			this.dimensions = {};
			this.dimensions.width = width;
			this.dimensions.height = height;

			this.elements = {};
			this.elements.resizeLeft    = resizeLeft;
			this.elements.resizeRight   = resizeRight;
			this.elements.grip			= grip;
			this.elements.container		= container;
		},

		/**
		 * makes sure this inside the event handler is the object
		 */
		bindEvent: function( element, eventName, functionName ){
			var self = this;
			var f = function( evt ){self[functionName](evt, self);};

			$(element).bind( eventName, f );
		}
	}

	$.fn.atHScaler = function( settings ) {
		this.each(function() {
			var config = $.extend( true, {}, $.fn.atHScaler.defaults, settings );
			var spin = new AtHScaler( this, config );
		});
		return this;
	};

	$.fn.atHScaler.defaults =  {
		range: {start: 0, max: 99},
		cycle: true,
		step: 1,
		attr: {
			'name': '',
			'value': 0,
			'id': '',
			'class': ''
		}
	}

	function identify(){
		return 'AtHScaler-' + ($('.atHScalerEnabled').length+1).toString();
	}

	function log( msg ){
		if( window.console ){
			console.log( msg );
		}
	}
})(jQuery);
